package com.supermap.component.impl;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.oro.text.regex.MalformedPatternException;

import com.supermap.commontypes.LocationInfo;
import com.supermap.commontypes.SampleInfo;
import com.supermap.component.LocalizationComponent;
import com.supermap.component.MatcherComponent;

public class LocalizationComponentImpl implements LocalizationComponent {

    private static Logger logger = Logger.getLogger(LocalizationComponentImpl.class);

    private MatcherComponent matcherComponent;

    private String[] beforeExcludePatterns;

    private String[] patterns;

    private String[] afterExcludePatterns;

    private Set<SampleInfo> sampleInfos = new HashSet<SampleInfo>();

    public LocalizationComponentImpl(String[] beforeExcludePatterns, String[] patterns, String[] afterExcludePatterns, MatcherComponent matcherComponent) {
        this.beforeExcludePatterns = beforeExcludePatterns;
        this.patterns = patterns;
        this.afterExcludePatterns = afterExcludePatterns;
        this.matcherComponent = matcherComponent;
    }

    public Set<SampleInfo> getSampleInfos() {
        return sampleInfos;
    }

    public Set<SampleInfo> extractSample(String srcDir) {
        Path srcPath = Paths.get(srcDir);
        try {
            Files.walkFileTree(srcPath, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                    try {
                        matcherSample(file);
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                        throw new RuntimeException(e);
                    }
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
        return sampleInfos;
    }

    public void updateKeyToFile(String srcDir, final List<SampleInfo> sampleInfos, final String desDir) {
        Path srcPath = Paths.get(srcDir);
        Path dest = Paths.get(desDir);
        
        try {
            Files.deleteIfExists(dest);
            Files.createDirectory(dest);
            Files.walkFileTree(srcPath, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    Path destFile = Paths.get(desDir, file.getFileName().toString());
                    if (Files.notExists(destFile)) {
                        Files.createFile(destFile);
                    }
                    BufferedReader br = null;
                    BufferedWriter bw = null;
                    try {
                        br = Files.newBufferedReader(file, StandardCharsets.UTF_8);
                        bw = Files.newBufferedWriter(destFile, StandardCharsets.UTF_8, StandardOpenOption.APPEND);
                        String line = null;
                        while ((line = br.readLine()) != null) {
                            line = updateAllKeyInStr(line, sampleInfos);
                            bw.write(line);
                            bw.newLine();
                        }
                    } catch (MalformedPatternException e) {
                        logger.error(e.getMessage(), e);
                        throw new RuntimeException(e);
                    } finally {
                        bw.close();
                        br.close();
                    }
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    // 用整个sample挨个处理str，使被翻译(优先处理较长字符串)
    private String updateAllKeyInStr(String str, List<SampleInfo> sampleInfos) throws MalformedPatternException {
        sampleInfos = sortByDesc(sampleInfos);
        String result = str;
        // 排除逻辑有待完善
        for (String excludePattern : beforeExcludePatterns) {
            if (matcherComponent.containsRegex(result, excludePattern)) {
                return result;
            }
        }
        for (int i = sampleInfos.size() - 1; i >= 0; i--) {
            result = StringUtils.replace(result, sampleInfos.get(i).getKey(), sampleInfos.get(i).getValue());
        }
        return result;
    }

    // 根据SampleInfo中的key值长度排序
    private List<SampleInfo> sortByDesc(List<SampleInfo> sampleInfos) {
        Collections.sort(sampleInfos, new Comparator<SampleInfo>() {

            public int compare(SampleInfo arg0, SampleInfo arg1) {
                return arg0.getKey().length() - arg1.getKey().length();
            }

        });
        return sampleInfos;
    }

    private void matcherSample(Path file) throws IOException, MalformedPatternException {
        BufferedReader br = null;
        br = Files.newBufferedReader(file, StandardCharsets.UTF_8);
        String line = null;
        int lineNum = 0;

        try {
            while ((line = br.readLine()) != null) {
                Set<String> result = getMatcherStr(line);
                for (String str : result) {
                    boolean isExist = false;// 判断是否已存在
                    for (SampleInfo info : sampleInfos) {
                        if (info.getKey().equals(str)) {
                            LocationInfo locationInfo = new LocationInfo();
                            locationInfo.setFileName(file.toString());
                            locationInfo.setLineNum(lineNum);
                            info.getLocation().add(locationInfo);
                            isExist = true;
                            break;
                        }
                    }
                    if (!isExist) {
                        SampleInfo sampleInfo = new SampleInfo();
                        sampleInfo.setKey(str);
                        sampleInfo.setValue(str);
                        List<LocationInfo> location = new ArrayList<LocationInfo>();
                        LocationInfo locationInfo = new LocationInfo();
                        locationInfo.setFileName(file.toString());
                        locationInfo.setLineNum(lineNum);
                        location.add(locationInfo);
                        sampleInfo.setLocation(location);
                        sampleInfos.add(sampleInfo);
                    }
                }
                lineNum++;
            }
        } finally {
            br.close();
        }
    }

    private Set<String> getMatcherStr(String srcStr) throws MalformedPatternException {
        Set<String> result = new HashSet<String>();

        for (int i = 0; i < beforeExcludePatterns.length; i++) {
            srcStr = matcherComponent.deleteMatchStr(srcStr, beforeExcludePatterns[i]);
        }

        for (int i = 0; i < patterns.length; i++) {
            Set<String> matchStr = matcherComponent.getMatcherStr(srcStr, patterns[i]);

            for (String str : matchStr) {
                boolean shouldExclude = false;
                for (int k = 0; k < afterExcludePatterns.length; k++) {
                    if (matcherComponent.containsRegex(str, afterExcludePatterns[k])) {
                        shouldExclude = true;
                        break;
                    }
                }
                if (!shouldExclude) {
                    result.add(str);
                    srcStr = srcStr.replace(str, "");// 删除已经匹配的字符串
                }
            }
        }

        return result;
    }

}
